interface Cache {
  get: (key: string) => any
  set: <T>(key: string, value: T, expire: number) => T
  del: (key: string) => any
}
type Expire = number | undefined | `${number}m` | `${number}h` | `${number}d`
interface CacheConfig {
  prefix: string
  expire: Expire
}
// 定义 this 的类型
interface CacheContext {
  request?: {
    path: string
  }
}

export function useCache(cache: Cache, { prefix: cacheKeyPrefix = '', expire: globalExpire = 0 } = {} as CacheConfig) {
  return function <R>(
    this: CacheContext | void,
    key: string,
    func: (cacheKey?: string) => R | Promise<R>,
    config?: Expire | { expire?: Expire, clearCache?: boolean },
  ): Promise<R> | R {
    // 参数校验
    if (typeof key !== 'string' || key === '') {
      throw new Error('Invalid cache key')
    }
    if (typeof func !== 'function') {
      throw new TypeError('func must be a function')
    }

    const prefix = `${cacheKeyPrefix}${this?.request?.path || ''}@@`
    key = prefix + key
    let expire: Expire
    if (typeof config === 'object') {
      expire = (config as { expire?: Expire, clearCache?: boolean }).expire
      if (config.clearCache) {
        cache.del(key)
      }
    }
    else {
      expire = config
    }
    const cached = cache.get(key)
    if (cached) return cached

    try {
      const result = func(key)
      if (result instanceof Promise) {
        return result.then(data => cache.set(key, data, parseExpire(expire || globalExpire)))
      }
      return cache.set(key, result, parseExpire(expire || globalExpire))
    }
    catch (error: any) {
      throw new Error(`Function execution failed for cache key "${key}": ${error.message}`)
    }
  }
}

function parseExpire(expire: number | undefined | `${number}m` | `${number}h` | `${number}d`) {
  let timeout = 0
  if (typeof expire === 'number') {
    timeout = expire
  }
  else if (typeof expire === 'string') {
    const num = Number.parseInt(expire.slice(0, -1))
    if (expire.endsWith('m')) {
      timeout = num * 60 * 1000
    }
    else if (expire.endsWith('h')) {
      timeout = num * 60 * 60 * 1000
    }
    else if (expire.endsWith('d')) {
      timeout = num * 24 * 60 * 60 * 1000
    }
  }
  return timeout
}

// const mapCache = new Map()
// const cache = useCache({
//   set: (key, data, expire) => {
//     const iat = Date.now()
//     let exp
//     if (expire > 0) {
//       exp = iat + expire
//     }
//     mapCache.set(key, { data, exp, iat })
//     return data
//   },
//   get: (key) => {
//     const cache = mapCache.get(key)
//     if (!cache) return null
//     if (cache.exp && Date.now() > cache.exp) {
//       mapCache.delete(key)
//       return null
//     }
//     return cache.data
//   },
//   del: (key) => {
//     mapCache.delete(key)
//   },
// })

// const res = cache('aaaa', () => {
//   return {
//     a: 1,
//     b: 5,
//   }
// })
// console.log(res)
